/*
* @Author: Jimmy
* @LastModifiedBy: Jimmy
* @Date: 2024-05-25 19:29:07
 * @LastEditTime: 2024-08-22 22:30:05
 * @FilePath: /nest_study/server/src/modules/system/menu/menu.service.ts
*/
import { Injectable } from '@nestjs/common';
import { CreateMenuDto } from './dto/index.dto';
import { SystemMenuEntity } from './entities/menu.entity';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { DeleteMenuDto, QueryMenuDto, UpdateMenuDto } from './dto/index.dto';
import { ResultData } from 'src/common/utils/result';
import { ListToTree } from 'src/common/utils';
import { SystemRoleEntity } from '../role/entities/role.entity';
import { LOGIN_TOKEN_EXPIRESIN } from 'src/common/constant';
import { CacheService } from 'src/modules/cache/cache.service';

@Injectable()
export class MenuService {
  constructor(
    @InjectRepository(SystemMenuEntity)
    private readonly menuRepo: Repository<SystemMenuEntity>,
    @InjectRepository(SystemRoleEntity)
    private readonly roleRepo: Repository<SystemRoleEntity>,
    private readonly cacheService: CacheService,
  ) { }
  // 创建
  async create(createMenuDto: CreateMenuDto) {
    let { parentId = -1, name } = createMenuDto;
    if (!parentId || !name) {
      return ResultData.fail(500, '缺少参数');
    }
    let parent = this.menuRepo.findOne({ where: { parentId: parentId } });
    if (!parent && parentId != -1) {
      return ResultData.fail(500, '父级菜单不存在');
    }
    await this.menuRepo.save(createMenuDto);
    await this.findAllAndCache();
    return ResultData.ok();
  }
  //列表
  async query(query: QueryMenuDto) {
    let { name } = query;
    let entity = this.menuRepo.createQueryBuilder('menu');
    if (name) {
      entity.andWhere(`menu.name LIKE "%${name}%"`);
    }
    let data = await entity.getMany();
    const treeData = ListToTree(data, (m: UpdateMenuDto) => m.id, (m: UpdateMenuDto) => m.name);
    return ResultData.ok(treeData);
  }
  //更新
  async update(updateMenuDto: UpdateMenuDto) {
    let { id, parentId, name, path } = updateMenuDto;
    if (!parentId || !name || !id) {
      return ResultData.fail(500, '缺少参数');
    }
    let result = await this.menuRepo.findOne({
      where: { name }
    });
    if (result && result?.id != id) {
      return ResultData.fail(500, '菜单名称已存在')
    }
    let pathResult = await this.menuRepo.findOne({
      where: { path }
    });
    if (pathResult && pathResult?.id != id) {
      return ResultData.fail(500, '菜单路径已存在')
    }
    let parent = this.menuRepo.findOne({ where: { parentId: parentId } });
    if (!parent && parentId != -1) {
      return ResultData.fail(500, '父级菜单不存在');
    }
    let menuInfo = await this.menuRepo.findOne({
      where: {
        id
      }
    });
    if (!menuInfo) {
      return ResultData.fail(500, '更新的菜单不存在');
    }
    delete updateMenuDto.children;
    let res = await this.menuRepo.update({ id }, updateMenuDto);
    await this.findAllAndCache();
    if (res.affected) {
      return ResultData.ok('更新成功');
    } else {
      return ResultData.fail(500, '更新失败')
    }
  }
  //删除
  async remove(info: DeleteMenuDto) {
    let { ids = [] } = info;
    if (ids.length == 0) {
      return ResultData.fail(500, '参数错误')
    }
    let total = 0;
    let subNum = 0;
    for (let i = 0; i < ids.length; i++) {
      let id = ids[i];
      let menuEntity = this.menuRepo.createQueryBuilder('menu').where("menu.parentId=:menuId", { menuId: id });
      let menuNum = await menuEntity.getCount();
      if (menuNum) {
        subNum += menuNum;
      } else {
        let entity = this.roleRepo.createQueryBuilder('role');
        entity.where("JSON_CONTAINS(role.menuIds,JSON_OBJECT('menuId', :value))", { value: id });
        let num = await entity.getCount();
        total += num;
      }
    }
    if (subNum) {
      return ResultData.fail(500, '请先删除子菜单')
    }
    if (total) {
      return ResultData.fail(500, '菜单正在被使用')
    }
    await this.menuRepo.delete(ids);
    await this.findAllAndCache();
    return ResultData.ok();
  }

  //查询全部菜单信息并缓存
  async findAllAndCache() {
    let entity = this.menuRepo.createQueryBuilder('menu');
    const [list] = await entity.getManyAndCount();
    this.cacheService.storeSet('sys_menus', list, LOGIN_TOKEN_EXPIRESIN)
  }
}
